package com.nali.dal.mongo.explain.query;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.nali.dal.expression.query.Criteria;

/**
 * Group<br>&nbsp;
 * 抽象mongodb api的group方法的参数对象
 * @author sam Created on 2011-3-8
 */
public class Group {
	private DBObject initial;
	private String reduce;
	private String finalize;
	private Group(DBObject initial, String reduce, String finalize) {
		super();
		this.initial = initial;
		this.reduce = reduce;
		this.finalize = finalize;
	}
	public static Group getGroup(Criteria criteria, String propertyName) {
		return getGroup(criteria, propertyName, propertyName+"_"+criteria);
	}
	public static Group getGroup(Criteria criteria, String propertyName, String alias) {
		switch (criteria) {
		case max:
			return max(propertyName, alias);
		case min:
			return min(propertyName, alias);
		case avg:
			return avg(propertyName, alias);
		case sum:
			return sum(propertyName, alias);
		case count:
			return count(propertyName, alias);
		default:
			throw new IllegalArgumentException("not supported criteria:" + criteria);
		}
	}
	public static StringBuilder appendReduceHead(StringBuilder sb) {
		return sb.append("function(cur, out) {");
	}
	public static StringBuilder appendFinalizeHead(StringBuilder sb) {
		return sb.append("function(out) {");
	}
	public static StringBuilder appendFunctionTail(StringBuilder sb) {
		return sb.append("}");
	}
	
	//TODO 改成stringbuilder
	//NALI_TODO (wujiajun) 1.stringbuilder 2.">","?",":","out."....
	public static Group max(String propName, String alias) {
		String maxProp="out." + alias;
		String curProp="cur." + propName;
		String reduce = maxProp + "=" + maxProp + ">" + curProp + "?" + maxProp + ":" + curProp;
		return new Group(null, reduce, "");
	}
	public static Group min(String propName, String alias) {
		String minProp="out." + alias;
		String curProp="cur." + propName;
		String reduce = minProp + "=" + minProp + "<" + curProp + "?" + minProp + ":" + curProp;
		return new Group(null, reduce, "");
	}
	public static Group sum(String propName, String alias) {
		String sumProp="out." + alias;
		String curProp="cur." + propName;
		DBObject initial=new BasicDBObject(alias, 0);
		String reduce=sumProp+"+=" + curProp + "||0";
		return new Group(initial, reduce, "");
	}
	public static Group avg(String propName, String alias) {
		String aliasCnt=alias + "_cnt";
		String avgProp="out." + alias;
		String cntProp="out." + aliasCnt;
		String curProp="cur." + propName;
		DBObject initial=new BasicDBObject(alias, 0).append(aliasCnt, 0);
		String reduce =	avgProp + "+=" + curProp + "||0;" +
						cntProp + "++";
		String finalize = avgProp + "/=(" + cntProp + "==0?1:" + cntProp + ")";
		return new Group(initial, reduce, finalize);
	}
	public static Group count(String propName, String alias) {
		DBObject initial=new BasicDBObject(alias, 0);
		String cntProp="out." + alias;
		String reduce= cntProp + "++";
		String finalize="";
		return new Group(initial, reduce, finalize);
	}
	public static Group minRow(String[] props, String[] aliases) {
		String minProp="out." + aliases[0];
		String curProp="cur." + props[0];
		StringBuilder reduce = new StringBuilder();
		reduce.append("if(!(").append(minProp).append("<=").append(curProp).append(")) {");
		for (int i = 0; i < aliases.length; i++) {
			String alias = aliases[i];
			String prop = props[i];
			reduce.append("out.").append(alias).append("=cur.").append(prop).append(";");
		}
		reduce.append("}");
		return new Group(null, reduce.toString(), "");
	}
	public static Group maxRow(String[] props, String[] aliases) {
		String maxProp="out." + aliases[0];
		String curProp="cur." + props[0];
		StringBuilder reduce = new StringBuilder();
		reduce.append("if(!(").append(maxProp).append(">=").append(curProp).append(")) {");
		for (int i = 0; i < aliases.length; i++) {
			String alias = aliases[i];
			String prop = props[i];
			reduce.append("out.").append(alias).append("=cur.").append(prop).append(";");
		}
		reduce.append("}");
		return new Group(null, reduce.toString(), "");
	}
	
	public DBObject getInitial() {
		return initial;
	}
	public String getReduce() {
		return reduce;
	}
	public String getFinalize() {
		return finalize;
	}
	public static Group getGroup(Criteria criteria, String[] props) {
		String[] aliases=new String[props.length];
		String tail="_"+criteria;
		for (int i = 0; i < aliases.length; i++) {
			aliases[i]=props[i]+tail;
		}
		return getGroup(criteria, props, aliases);
	}
	public static Group getGroup(Criteria criteria, String[] props, String[] aliases) {
		switch (criteria) {
		case maxRow:
			return maxRow(props, aliases);
		case minRow:
			return minRow(props, aliases);
		default:
			throw new IllegalArgumentException("not supported criteria:" + criteria);
		}
	}
}
